package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
//import com.iwhalecloud.citybrain.flow.platform.manager.application.event.EventResponse;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.StringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.model.EventResponse;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.BeanCopierUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.DateUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.exception.EventCallException;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.ProcessQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.eventconfig.EventExceptionDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowEventExceptionRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowEventException;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowEventExceptionExample;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowEventExceptionDAO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Repository;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

import static com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode.BAD_REQUEST;

/**
　　* @description: 事件异常数据持久化实现类
　　* @author shenrm
　　* @date 2022/5/9 18:19
　　*/
@Slf4j
@Repository
public class FlowEventExceptionRepositoryImpl implements FlowEventExceptionRepository {

    @Autowired
    private FlowEventExceptionDAO flowEventExceptionDAO;

    @Autowired
    private RestTemplate restTemplate;
    @Value("${feign.task.appCode}")
    private String  appCode;
    @Value("${feign.task.appAccessKey}")
    private String appAccessKey;


    /**
     * 插入信息
     *
     * @param eventException 事件异常信息
     * @return
     */
    @Override
    public void insertEventException(EventExceptionDomain eventException) {
        FlowEventException entity = new FlowEventException();
        BeanCopierUtils.copyProperties(eventException, entity);
        entity.setGmtCreate(new Date());
        entity.setGmtModified(new Date());
        try {
            log.info("insertEventException entity:"+JSONObject.toJSONString(entity));
            log.info("flowEventExceptionDAO:"+flowEventExceptionDAO);
            flowEventExceptionDAO.insert(entity);
        } catch (Exception ex) {
            log.info("insertEventException 新增数据异常:" + ex.getMessage());
        }
        return;
    }

    /**
     * 根据条件查询数据列表
     *
     * @param processQueryVo
     * @return
     */
    @Override
    public List<EventExceptionDomain> queryEventExceptionList(ProcessQueryVo processQueryVo) {
        PageHelper.startPage(processQueryVo.getPageNum(), processQueryVo.getPageSize());
        FlowEventExceptionExample queryCondition = new FlowEventExceptionExample();
        // 添加条件
        FlowEventExceptionExample.Criteria criteria = queryCondition.createCriteria();

        // 模型编码
        if(StringUtils.isNotBlank(processQueryVo.getModelKey())) {
            criteria.andModelKeyEqualTo(processQueryVo.getModelKey());
        }
        //流程实例id
        if(StringUtils.isNotBlank(processQueryVo.getProcessInstanceId())) {
            criteria.andProcessInstanceIdEqualTo(processQueryVo.getProcessInstanceId());
        }

        //事件名称
        if(StringUtils.isNotBlank(processQueryVo.getName())) {
            criteria.andNameEqualTo(processQueryVo.getName());
        }
        //模型id
        if(StringUtils.isNotBlank(processQueryVo.getModelId())) {
            criteria.andModelIdEqualTo(processQueryVo.getModelId());
        }

        // 模型名称
        if(StringUtils.isNotBlank(processQueryVo.getModelName())) {
            criteria.andModelNameLike(processQueryVo.getModelName());
        }

        // 节点编码
        if(StringUtils.isNotBlank(processQueryVo.getNodeCode())) {
            criteria.andNodeCodeEqualTo(processQueryVo.getNodeCode());
        }

        // 事件类型
        if(StringUtils.isNotBlank(processQueryVo.getEventType())) {
            criteria.andEventTypeEqualTo(processQueryVo.getEventType());
        }

        // 同步/异步
        if(StringUtils.isNotBlank(processQueryVo.getCallMethod())) {
            criteria.andCallMethodEqualTo(processQueryVo.getCallMethod());
        }
        // 查询时间段
        if(StringUtils.isNotBlank(processQueryVo.getTimeStart()) &&
                StringUtils.isNotBlank(processQueryVo.getTimeEnd())) {
            // 查询开始时间
            Date timeStart = DateUtils.TimestampToDate(processQueryVo.getTimeStart());
            // 查询结束时间
            Date timeEnd = DateUtils.TimestampToDate(processQueryVo.getTimeEnd());
            criteria.andGmtCreateBetween(timeStart, timeEnd);
        }
        //添加补偿状态的查询条件
        if(StringUtils.isNotBlank(processQueryVo.getStatus())){
            criteria.andStatusEqualTo(processQueryVo.getStatus());
        }

        // 默认按照创建时间倒序
        queryCondition.setOrderByClause("gmt_create desc");
        return getPageableResult(getRecords(queryCondition));
    }

    @Override
    public EventResponse restTemplateRequest(String requestUrl, String requestBody,int id) throws EventCallException {
        log.info(String.format("restTemplateRequest req: url = %s, requestBody = %s",requestUrl,requestBody));
        ResponseEntity<EventResponse> eventResponse = null;
        FlowEventException flowEventException=flowEventExceptionDAO.selectById(id);
        try {
            if(Objects.nonNull(flowEventException) && StringUtils.isNotBlank(flowEventException.getEventType()) && flowEventException.getEventType().contains("待办")){
                log.info("****待办异常补偿********,异常信息：{}",flowEventException);
                eventResponse = restTemplate.exchange(requestUrl, HttpMethod.POST,buildHttpEntityForTask(requestBody), EventResponse.class);
            }
            else{
                log.info("****节点前后置事件异常补偿********");
                eventResponse = restTemplate.exchange(requestUrl, HttpMethod.POST,buildHttpEntity(requestBody), EventResponse.class);
            }
        } catch (RestClientException e) {
            log.error("execute exchange error:",e);
            throw new EventCallException("事件接口调用异常："+ StringUtils.changeStringEncodingFromGBKToUTF8(e.getMessage()));
        }
        if (Objects.nonNull(eventResponse)){
            if (!Objects.equals(org.apache.http.HttpStatus.SC_OK,eventResponse.getStatusCodeValue())){
                throw new EventCallException("事件接口调用失败");
            }else{
                log.info("call exchange success!");
            }
            log.info("restTemplateResponse:"+ JSON.toJSONString(eventResponse));
//            if(eventResponse.getBody() == null) {
//                return false;
//            }
//            return eventResponse.getBody().isSuccess();
        }
        return eventResponse.getBody();
    }

    @Override
    public int updateByPrimaryKeySelective(EventExceptionDomain eventException) {
        FlowEventException entity = new FlowEventException();
        BeanCopierUtils.copyProperties(eventException, entity);
        try {
            return flowEventExceptionDAO.updateByPrimaryKeySelective(entity);
        } catch (Exception ex) {
            log.info("updateByPrimaryKeySelective 修改数据异常:" + ex.getMessage());
        }
        return 0;
    }

    /**
     * 组织请求参数
     *
     * @param requestBody
     * @return
     */
    private HttpEntity<String> buildHttpEntity(String requestBody){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAcceptCharset(Collections.singletonList(Charset.forName("utf-8")));
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        return new HttpEntity(requestBody,headers);
    }

    private HttpEntity<String> buildHttpEntityForTask(String requestBody){
        //待办信息同步待办组件需要添加头部信息，头部信息对其他不需要头部信息的接口没有影响
        MultiValueMap<String, String> temp=new LinkedMultiValueMap<>();
        temp.add("app-code",appCode);
        temp.add("app-access-key",appAccessKey);
        HttpHeaders headers = new HttpHeaders(temp);
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAcceptCharset(Collections.singletonList(Charset.forName("utf-8")));
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        return new HttpEntity(requestBody,headers);
    }

    /**
     * 获取记录列表
     * @param queryCondition
     * @return
     */
    public List<FlowEventException> getRecords(FlowEventExceptionExample queryCondition) {
        if (Objects.isNull(queryCondition)) {
            return null;
        }
        return flowEventExceptionDAO.selectByExample(queryCondition);
    }

    /**
     * 组装查询的分页结果
     * @param flowEventExceptions
     * @return
     */
    private List<EventExceptionDomain> getPageableResult(List<FlowEventException> flowEventExceptions) {
        PageInfo<FlowEventException> pageInfo = new PageInfo<>(flowEventExceptions);
        Page<EventExceptionDomain> result = null;
        try {
            result = new Page<>();
            result.setPageNum(pageInfo.getPageNum()).setPageSize(pageInfo.getPageSize()).addAll(convertObjData(flowEventExceptions));
            result.setTotal(pageInfo.getTotal());
            return result;
        } finally {
            if (Objects.nonNull(result)) {
                result.close();
            }
        }
    }

    /**
     * 对象数据转换
     * @param sources
     * @return
     */
    private List<EventExceptionDomain> convertObjData(List<FlowEventException> sources) {
        if(CollectionUtils.isEmpty(sources)) {
            return Collections.emptyList();
        }

        // 转换对象
        List<EventExceptionDomain> eventExceptionDomains = sources.stream().map(item -> {
            EventExceptionDomain eventExceptionDomain = new EventExceptionDomain();
            BeanUtils.copyProperties(item, eventExceptionDomain);
            return eventExceptionDomain;
        }).collect(Collectors.toList());
        return eventExceptionDomains;
    }

    @Override
    public ResponseResult processEventException(ProcessQueryVo processQueryVo){
        ResponseResult<String> responseResult = ResponseResult.success();
        try {
            processQueryVo.setPageSize(1000);
            List<EventExceptionDomain> eventExceptionDomainList = queryEventExceptionList(processQueryVo);
            //遍历eventExceptionDomainList
            for (EventExceptionDomain eventExceptionDomain : eventExceptionDomainList) {
                //获取异常信息中的任务id
                String url = eventExceptionDomain.getCallbackContent();
                String body = eventExceptionDomain.getRequestBody();
                if (StringUtils.isNotEmpty(url) && StringUtils.isNotEmpty(body)&& StringUtils.isNotEmpty(eventExceptionDomain.getEventType()) && (eventExceptionDomain.getEventType().contains("待办") )) {//
                    ResponseEntity<EventResponse> eventResponse = null;
                    try {
                        eventResponse = restTemplate.exchange(url, HttpMethod.POST,buildHttpEntityForTask(body), EventResponse.class);
                        // 处理成功,更新补偿状态
                        if (eventResponse != null && Objects.equals(org.apache.http.HttpStatus.SC_OK,eventResponse.getStatusCodeValue())) {
                            // 使用主键id更新记录,状态修改成已补偿
                            eventExceptionDomain.setStatus("1");
                            updateByPrimaryKeySelective(eventExceptionDomain);
                        }
                    }catch (RestClientException e) {
                        log.error("execute exchange error:",e);
                        throw new EventCallException("事件接口调用异常："+ StringUtils.changeStringEncodingFromGBKToUTF8(e.getMessage()));
                    }

                }
            }

        } catch (Exception e) {
            log.error("processEventException error", e);
            return ResponseResult.fail(BAD_REQUEST.errCode(), e.getMessage());
        }
        log.info("processEventException Response:" + JSONObject.toJSONString(responseResult));
        return responseResult;

    }

}
